package com.example.adsharmonyos;


import com.example.adsharmonyos.util.HiExecutor;
import ohos.ace.ability.AceInternalAbility;
import ohos.app.AbilityContext;
import ohos.app.dispatcher.TaskDispatcher;
import ohos.app.dispatcher.task.TaskPriority;
import ohos.data.distributed.common.*;
import ohos.data.distributed.user.SingleKvStore;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import ohos.net.NetHandle;
import ohos.net.NetManager;
import ohos.rpc.IRemoteObject;
import ohos.rpc.MessageOption;
import ohos.rpc.MessageParcel;
import ohos.rpc.RemoteException;
import ohos.utils.zson.ZSONObject;
import ohos.wifi.IpInfo;
import ohos.wifi.WifiDevice;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

public class KvStoreAbility extends AceInternalAbility {
    private static final String BUNDLE_NAME = "com.example.adsharmonyos";
    private static final String ABILITY_NAME = "com.example.adsharmonyos.KvStoreAbility";
    private AbilityContext abilityContext;
    private IRemoteObject remoteObjectHandler;
    private static KvStoreAbility instance;
    private static final HiLogLabel LABEL = new HiLogLabel(0, 0, "=>JAVA:" );
    private static final int SUCCESS = 0;
    private static final int SUBSCRIBE = 1005;
    private static final int UNSUBSCRIBE = 1006;
    private static final int SYNC = 1007;
    private static final int KVSTORE = 1008;
    private static final int SHARE = 1009;
    private static final int UDP=1010;
    private  int isNew = 0;

    private KvManagerConfig config;
    private KvManager kvManager;
    private SingleKvStore singleKvStore;

    private String MESSAGE_KV_SUCCESS = "KV_SUCCESS";
    private String MESSAGE_SUB_SUCCESS="SUBS_SUCCESS";
    private String ACCEPT_CARD_SUCCESS="接受卡片成功";
    private String storeId = "ScoreStore";

    private String card="";
    public KvStoreAbility() {
        super(BUNDLE_NAME,ABILITY_NAME);
    }
    public boolean onRemoteRequest(int code, MessageParcel data, MessageParcel reply, MessageOption option) throws RemoteException {
        switch (code) {
            // 开启订阅，保存对端的remoteHandler，用于上报数据
            case SUBSCRIBE: {
                // 如果仅支持单FA订阅，可直接覆盖：remoteObjectHandler = data.readRemoteObject();
                remoteObjectHandler=data.readRemoteObject();
                card=data.readString();
                startNotify();
                Map<String, Object> result = new HashMap<String, Object>();
                result.put("code", SUCCESS);

                // SYNC
                if (option.getFlags() == MessageOption.TF_SYNC) {
                    reply.writeString(ZSONObject.toZSONString(result));
                } else {
                    //ASYNC
                    MessageParcel responseData = MessageParcel.obtain();
                    responseData.writeString(ZSONObject.toZSONString(result));
                    IRemoteObject remoteReply = reply.readRemoteObject();
                    try {
                        remoteReply.sendRequest(0, responseData, MessageParcel.obtain(), new MessageOption());
                        responseData.reclaim();
                    } catch (RemoteException exception) {
                        return false;
                    }
                }
                //subscribeEvent(data, reply, option);
                break;
            }
            // 取消订阅，置空对端的remoteHandler
            case UNSUBSCRIBE: {
                // 如果仅支持单FA订阅，可直接置空：remoteObjectHandler = null;
                remoteObjectHandler=null;
                //thread.stop();
                Map<String, Object> result = new HashMap<String, Object>();
                result.put("code", SUCCESS);
                // SYNC
                if (option.getFlags() == MessageOption.TF_SYNC) {
                    reply.writeString(ZSONObject.toZSONString(result));
                } else {
                    //ASYNC
                    MessageParcel responseData = MessageParcel.obtain();
                    responseData.writeString(ZSONObject.toZSONString(result));
                    IRemoteObject remoteReply = reply.readRemoteObject();
                    try {
                        remoteReply.sendRequest(0, responseData, MessageParcel.obtain(), new MessageOption());
                        responseData.reclaim();
                    } catch (RemoteException exception) {
                        return false;
                    }
                }
                break;
            }
            case UDP:{
                initServer();
                send();
                Map<String, Object> result = new HashMap<String, Object>();
                result.put("code", SUCCESS);
                result.put("abilityResult", "UDPSUCCESS");
                // SYNC
                if (option.getFlags() == MessageOption.TF_SYNC) {
                    reply.writeString(ZSONObject.toZSONString(result));
                } else {
                    // ASYNC
                    MessageParcel responseData = MessageParcel.obtain();
                    responseData.writeString(ZSONObject.toZSONString(result));
                    IRemoteObject remoteReply = reply.readRemoteObject();
                    try {
                        remoteReply.sendRequest(0, responseData, MessageParcel.obtain(), new MessageOption());
                    } catch (RemoteException exception) {
                        return false;
                    } finally {
                        responseData.reclaim();
                    }
                }
                break;
            }
            //协同播放
            case SYNC: {
                String dataStr = data.readString();
                 card=dataStr;
//                 initServer();
                 send();
               /* RequestParam param = new RequestParam();
                try {
                    param = ZSONObject.stringToClass(dataStr, RequestParam.class);
                } catch (RuntimeException e) {
                    HiLog.error(LABEL, "convert failed.");
                }*/

                HiLog.debug(LABEL, "卡片"+dataStr);



                Map<String, Object> result = new HashMap<String, Object>();
                result.put("code", SUCCESS);
                result.put("abilityResult", ACCEPT_CARD_SUCCESS);
                result.put("card",dataStr);
                // SYNC
                if (option.getFlags() == MessageOption.TF_SYNC) {
                    reply.writeString(ZSONObject.toZSONString(result));
                } else {
                    // ASYNC
                    MessageParcel responseData = MessageParcel.obtain();
                    responseData.writeString(ZSONObject.toZSONString(result));
                    IRemoteObject remoteReply = reply.readRemoteObject();
                    try {
                        remoteReply.sendRequest(0, responseData, MessageParcel.obtain(), new MessageOption());
                    } catch (RemoteException exception) {
                        return false;
                    } finally {
                        responseData.reclaim();
                    }
                }
                break;
            }
            //创建分布式数据库
            case KVSTORE:{
                init();
                Map<String, Object> result = new HashMap<String, Object>();
                result.put("code", SUCCESS);
                result.put("abilityResult", MESSAGE_KV_SUCCESS);
                // SYNC
                if (option.getFlags() == MessageOption.TF_SYNC) {
                    reply.writeString(ZSONObject.toZSONString(result));
                } else {
                    // ASYNC
                    MessageParcel responseData = MessageParcel.obtain();
                    responseData.writeString(ZSONObject.toZSONString(result));
                    IRemoteObject remoteReply = reply.readRemoteObject();
                    try {
                        remoteReply.sendRequest(0, responseData, MessageParcel.obtain(), new MessageOption());
                    } catch (RemoteException exception) {
                        return false;
                    } finally {
                        responseData.reclaim();
                    }
                }
                break;
            }
            case SHARE:{

            }
            default: {
                reply.writeString("Service not defined");
                return false;
            }
        }
        return true;
    }
    public void init(){
        // 创建分布式数据库管理对象
        config = new KvManagerConfig(abilityContext);
        kvManager = KvManagerFactory.getInstance().createKvManager(config);
        // 创建分布式数据库
        try {
            Options options = new Options();
            options.setCreateIfMissing(true).setEncrypt(false).setKvStoreType(KvStoreType.SINGLE_VERSION).setAutoSync(true);
            String storeId = "testApp";
            singleKvStore = kvManager.getKvStore(options, storeId);

        } catch (KvStoreException e) {
            HiLog.warn(LABEL,  "getKvStore:" + e.getKvStoreErrorCode());
        }


        // 订阅分布式数据变化
        KvStoreObserver kvStoreObserverClient = new KvStoreObserverClient();
        singleKvStore.subscribe(SubscribeType.SUBSCRIBE_TYPE_ALL, kvStoreObserverClient);


        //singleKvStore.putString(PLAY_REMOTE,"NO");

        //deviceInfoList = kvManager.getConnectedDevicesInfo(DeviceFilterStrategy.NO_FILTER);
        // return MESSAGE_KV_SUCCESS;
    }
    private class KvStoreObserverClient implements KvStoreObserver {
        @Override
        public void onChange(ChangeNotification notification) {

            List<Entry> updateEntries = notification.getUpdateEntries();
            if(updateEntries.size()!=0){
                for(int i=0;i<updateEntries.size();i++){

                       card=updateEntries.get(i).getValue().getString();
                       HiLog.debug(LABEL, "获取到新卡片"+card);
                       isNew=1;
                }

            }
            //card = notification.getUpdateEntries().get(0).getValue().getString();

            HiLog.debug(LABEL, "Change....."+notification.getUpdateEntries().size());

        }
    }
    public void boardcast(){
        singleKvStore.putString("newCard",card);
    }

    public void startNotify() {
        Thread thread = new Thread(() -> {
            while (true) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if(isNew==1){
                    try {
                        testReportEvent();
                         isNew=0;
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                }


            }
        });
        thread.start();
    }
    private void testReportEvent() throws RemoteException {
        MessageParcel  data = MessageParcel.obtain();
        MessageParcel reply = MessageParcel.obtain();
        MessageOption option = new MessageOption();
        Map<String, Object> event = new HashMap<String, Object>();
        event.put("newCard",card);
        HiLog.debug(LABEL, "发送信息"+card);
        data.writeString(ZSONObject.toZSONString(event));
        // 如果仅支持单FA订阅，可直接触发回调：remoteObjectHandler.sendRequest(100, data, reply, option);
        remoteObjectHandler.sendRequest(100, data, reply, option);
        reply.reclaim();
        data.reclaim();

    }
    /**
     * Internal ability 注册接口。
     */
    public static void register(AbilityContext abilityContext) {
        instance = new KvStoreAbility();
        instance.onRegister(abilityContext);
    }

    private void onRegister(AbilityContext abilityContext) {
        this.abilityContext = abilityContext;
        this.setInternalAbilityHandler((code, data, reply, option) -> {
            return this.onRemoteRequest(code, data, reply, option);
        });
    }
    private void send() {
        TaskDispatcher globalTaskDispatcher = abilityContext.getGlobalTaskDispatcher(TaskPriority.DEFAULT);
        globalTaskDispatcher.delayDispatch(new Runnable() {
            @Override
            public void run() {
                NetManager netManager = NetManager.getInstance(abilityContext);

                if (!netManager.hasDefaultNet()) {
                    HiLog.error(LABEL,"netManager.hasDefaultNet() failed");
                    return;
                }
                NetHandle netHandle = netManager.getDefaultNet();

                // 通过Socket绑定来进行数据传输
                DatagramSocket socket = null;
                try {
                    String HOST="192.168.1.103";
                    InetAddress address = netHandle.getByName(HOST);
                    socket = new DatagramSocket();
                    netHandle.bindSocket(socket);
                    String data = unicode(card);

                    DatagramPacket request = new DatagramPacket(data.getBytes("UTF-8"), data.length(), address, 10006);
                    // buffer赋值
                    // 发送数据


                    socket.send(request);
                    HiLog.info(LABEL,"send data: " + data);

                } catch (IOException e) {

                    HiLog.error(LABEL,"send IOException: ");
                } finally {
                    if (null != socket) {

                    }
                }
            }
        },1000);
    }
    public static String unicode(String source){
        StringBuffer sb = new StringBuffer();
        char [] source_char = source.toCharArray();
        String unicode = null;
        for (int i=0;i<source_char.length;i++) {
            unicode = Integer.toHexString(source_char[i]);
            if (unicode.length() <= 2) {
                unicode = "00" + unicode;
            }
            sb.append("\\u" + unicode);
        }
        System.out.println(sb);
        return sb.toString();
    }
    private void initServer() {
        HiExecutor.runBG(new Runnable() {
            @Override
            public void run() {

                HiLog.info(LABEL,"initServer run"+getLocalIpAddress());
                NetManager netManager = NetManager.getInstance(null);

                if (!netManager.hasDefaultNet()) {

                    HiLog.error(LABEL,"netManager.hasDefaultNet() failed");
                    return;
                }
                NetHandle netHandle = netManager.getDefaultNet();
                DatagramSocket socket = null;
                // 通过Socket绑定来进行数据传输
                try {

                    HiLog.info(LABEL,"wait receive data");
                    InetAddress address = netHandle.getByName(getLocalIpAddress());
                    socket = new DatagramSocket(10006, address);
                    netHandle.bindSocket(socket);

                    HiLog.info(LABEL,"绑定成功");
                    byte[] buffer = new byte[9192];
                    DatagramPacket response = new DatagramPacket(buffer, buffer.length);

                     while(true){
                         //接收数据
                         socket.receive(response);

                         int len = response.getLength();
                         HiLog.info(LABEL, "接收成功");
                         //将数据打印到屏幕上
                         String s= new String(buffer, StandardCharsets.UTF_8);
                         s=s.substring(0,s.lastIndexOf('}')+1);
                         card="["+s+"]";

                         isNew=1;

                         HiLog.info(LABEL, "receive data: " + card);
                     }

                } catch (IOException e) {

                    HiLog.error(LABEL,"rev IOException: " );
                }
            }
        });

    }
    public static String decodeUnicode2(String dataStr) {
        int start = 0;
        int end = 0;
        final StringBuffer buffer = new StringBuffer();
        while (start > -1) {
            end = dataStr.indexOf("\\u", start + 2);
            String charStr = null;
            if (end == -1) {
                charStr = dataStr.substring(start + 2, dataStr.length());
            } else {
                charStr = dataStr.substring(start + 2, end);
            }
            char letter = (char) Integer.parseInt(charStr, 16);
            buffer.append(new Character(letter).toString());
            start = end;
        }
        return buffer.toString();
    }
    private String getLocalIpAddress() {
        WifiDevice wifiDevice = WifiDevice.getInstance(abilityContext);
        Optional<IpInfo> ipInfo = wifiDevice.getIpInfo();
        int ip = ipInfo.get().getIpAddress();
        return (ip & 0xFF) + "." + ((ip >> 8) & 0xFF) + "." + ((ip >> 16) & 0xFF) + "." + (ip >> 24 & 0xFF);
    }
    /**
     * Internal ability 注销接口。
     */
    public static void unregister() {

        instance.onUnregister();
    }

    private void onUnregister() {
        abilityContext = null;
        this.setInternalAbilityHandler(null);
    }

}
